#pragma once
#include <vector>
#include <string>
#include <fstream>
#include <cassert>
#include <cstdint>

#define ReadNBytes(f, b, n) (f.read(reinterpret_cast<const char*>(b), n))
#define Read4Bytes(f, b) (ReadNBytes(f, &b, 4))
#define WriteNBytes(f, b, n) (f.write(reinterpret_cast<const char*>(b), n))
#define Write4Bytes(f, b) (WriteNBytes(f, &b, 4))

class AnimationWriter {
public:
	//strand count
	//particle count
	//number of particle per strand
	//rigid transformation + particle position
	AnimationWriter(const std::string file_path, const std::vector<int> &particle_number_per_strand) {
		this->fout = std::ofstream(file_path, std::ios::binary | std::ios::out);
		if (this->fout.is_open() == false)
			assert(0);

		particle_count = 0;
		for (const auto &pc : particle_number_per_strand)
			particle_count += pc;

		int32_t write_strand_count = static_cast<int32_t>(particle_number_per_strand.size());
		int32_t write_particle_count = static_cast<int32_t>(particle_count);
		WriteNBytes(fout, &write_strand_count, 4);
		WriteNBytes(fout, &write_particle_count, 4);

		for (const auto &pc : particle_number_per_strand) {
			int32_t write_pc = static_cast<int32_t>(pc);
			WriteNBytes(fout, &write_pc, 4);
		}
	}

	AnimationWriter(const std::string file_path, int strand_count, const int particle_per_strand) : AnimationWriter(file_path, std::vector<int>(strand_count, particle_per_strand)) {}

	void close() {
		if (this->fout.is_open())
			this->fout.close();
	}

	void feed(const float *transformation, const float *positions) {
		WriteNBytes(fout, transformation, sizeof(float) * 16);
		WriteNBytes(fout, positions, sizeof(float) * 3 * particle_count);
	}

	~AnimationWriter() {
		this->close();
	}

protected:
	int particle_count;
	std::ofstream fout;
};